package commande.receiver;

import commande.commandes.Coller;
import commande.commandes.Command;
import commande.commandes.Copier;
import commande.commandes.Couper;
import commande.commandes.Deplacement;
import commande.commandes.SaisirTexte;
import commande.commandes.Selectionner;
import commande.commandes.Supprimer;

import observeur.Observeur;
import undo_redo.ConcreteMementoColler;
import undo_redo.ConcreteMementoCopier;
import undo_redo.ConcreteMementoCouper;
import undo_redo.ConcreteMementoSaisirTexte;
import undo_redo.ConcreteMementoSupprimer;
import undo_redo.EnregistreurUR;
import undo_redo.MementoUR;
import modele.Buffer;
import modele.Curseur;
import modele.Selection;
import modele.PressePapier;
import enregistre.ConcreteMemento;
import enregistre.Enregistreur;
import enregistre.Memento;

/**
 * Class EditeurImpl qui implemente l'interface Editeur
 */

public class EditeurImpl implements Editeur {

	private Buffer _buffer;
	private Observeur _observe;
	private Selection _selection;
	private Curseur _curseur;
	private PressePapier _pressePapier;
	private Enregistreur _enregistreur;
	private EnregistreurUR _enregistreurUR;
	private char _dernierCarac; // tampon du dernier caractere tape
	private Boolean _sup; //tampon permetant de savoir si on a sup ou del
	private int _dep; //tampon du deplacement a effectuer
	private String _eleSup=""; //tampon de la chaine supprimer lors d'un coller, saisirtext ou supprimer
	

	/**
	 * Constructeur qui initialise un buffer et son observeur pour mettre a jour l'IHM via le patron de conception
	 */
	
	public EditeurImpl(){
		_enregistreur = new Enregistreur();
		_enregistreurUR = new EnregistreurUR(this);
		_selection = new Selection();
		_curseur = new Curseur();
		_buffer = new Buffer(_curseur);
		_pressePapier = new PressePapier();
		_observe = new Observeur();
		_observe.init(_buffer,_curseur,_enregistreur,_selection);
	}
	
	/**
	 * Fonction appelle par la concrete commande SaisirTexte
	 * @param t char Le caractere tape.
	 */
	public void saisirText(char t) {
		_dernierCarac=t;
		if(_selection.getDebutSelect()!=_selection.getFinSelect()){
			supprimer(true);
		}
		_buffer.setCarac(t);
		_curseur.changeCurseur(_curseur.getEmplacement()+1);
	}

	/**
	 * Fonction appelle par la concrete commande Selectionner
	 * @param d int Represente le debut de la selection
	 * @param l int Represente la longueur de la selection
	 */
	public void selectionner(int d, int f) {
		_selection.setDebutSelect(d);
		_selection.setFinSelect(f);
	}

	/**
	 * Fonction appelle par la concrete commande Couper
	 */
	public void couper() {
		_pressePapier.set_PressePapier(_buffer.getBuffer().substring(_selection.getDebutSelect(), _selection.getFinSelect()));
		if(_curseur.getEmplacement()==_selection.getFinSelect()) this.deplacement(_curseur.getEmplacement() - _selection.getTailleSelection());
		_buffer.supSelect(_selection.getDebutSelect(), _selection.getFinSelect());
		_selection.setFinSelect(_selection.getDebutSelect());
	}

	/**
	 * Fonction appelle par la concrete commande Copier
	 */
	public void copier() {
		_pressePapier.set_PressePapier(_buffer.getBuffer().substring(_selection.getDebutSelect(), _selection.getFinSelect()));
	}

	/**
	 * Fonction appelle par la concrete commande Coller
	 */
	public void coller() {
		if(_selection.getDebutSelect()!=_selection.getFinSelect()){
			supprimer(true);
		}
		String chaine = _pressePapier.get_PressePapier();
		_buffer.setChaine(chaine);
		this.deplacement(_curseur.getEmplacement() + chaine.length());
	}
	
	/**
	 * Fonction qui met a jour la position du curseur
	 * @param dep int
	 */
	public void deplacement(int dep){
		_dep=dep;
		_curseur.changeCurseur(dep);
	}

	/**
	 * Fonction qui supprimme une chaine de caractere
	 * @param sup Boolean
	 */
	public void supprimer(Boolean sup) {
		_sup=sup;
		if(_selection.getDebutSelect()!=_selection.getFinSelect()){
			_eleSup=_buffer.getBuffer().substring(_selection.getDebutSelect(), _selection.getFinSelect()).toString();
			_curseur.changeCurseur(_selection.getDebutSelect());
			_buffer.supSelect(_selection.getDebutSelect(), _selection.getFinSelect());
			_selection.setFinSelect(_selection.getDebutSelect());
		}else{
			if(sup){
				int emp = _curseur.getEmplacement();
				if(emp>0){
					_eleSup=_buffer.getBuffer().substring(emp-1, emp);
					_curseur.changeCurseur(emp-1);
					_buffer.supCar(emp-1);
				}
			}else if(_curseur.getEmplacement()!=_buffer.length()){
				_eleSup=_buffer.getBuffer().substring(_curseur.getEmplacement(), _curseur.getEmplacement()+1);
				_buffer.supCar(_curseur.getEmplacement());
			}
		}
	}
	
	/**
	 * Fonction d'activation et de desactivation de l'enregistrement 
	 */
	public void enregistrer(){
		//Si le mode enregistrement est deja lance on va le stop
		if(_enregistreur.getModeEnregistrementActif()){
			_enregistreur.setModeEnregistrementActif(false);
		}
		//Si le mode enregistrement n'est pas deja lance on vide supprime l'enregistrement precedent et on lance un nouveau enregistrement
		else{
			_enregistreur.vider();
			_enregistreur.setModeEnregistrementActif(true);
		}
	}
	
	/**
	 * Fonction qui permet de rejouer l'enregistrement
	 */
	public void rejouer(){
		//aucun effet si le mode d'enregistrement et actif (securite)
		if(!_enregistreur.getModeEnregistrementActif()){
			_enregistreur.rejouer();
		}
	}
	
	/**
	 * Fonction permettant d'annuler la derniere action
	 */
	public void undo(){
		_enregistreurUR.defaire();
	}
	
	/**
	 * Fonction qui permet de regenerer l'action defaite
	 */
	public void redo(){
		_enregistreurUR.refaire();
	}
	
	/**
	 * get pour l'originator du memento pour la v2 (enregistrement)
	 * @param a Command
	 */	
	public void getMemento(Command a){
		Memento mem = new ConcreteMemento();
		mem.setCommand(a);
		if(a instanceof SaisirTexte){
			mem.set_carac(_dernierCarac);
		}else if(a instanceof Supprimer){
			mem.set_sup(_sup);
		}else if(a instanceof Selectionner){
			mem.set_selDeb(_selection.getDebutSelect());
			mem.set_selFin(_selection.getFinSelect());
		}else if(a instanceof Deplacement){
			mem.set_dep(_dep);
		}
		_enregistreur.addMemento(mem);
	}	
	
	/**
	 * set pour l'originator du memento pour la v2 (enregistrement)
	 * @param m Memento
	 */
	public void setMemento(Memento m) {
		Command c = m.getCommand();
		if(c instanceof SaisirTexte){
			saisirText(m.get_carac());
		}else if(c instanceof Supprimer){
			supprimer(m.get_sup());
		}else if(c instanceof Selectionner){
			selectionner(m.get_selDeb(),m.get_selFin());
		}else if(c instanceof Deplacement){
			deplacement(m.get_dep());
		}else{
			c.execute();
		}
	}
	
	/**
	 * get pour l'originator du memento pour la v3 (undo_redo)
	 * @param a Command
	 */	
	public void getMementoUR(Command a){
		MementoUR mem=null;
		if(a instanceof Coller){
			mem = new ConcreteMementoColler();
		}else if(a instanceof Copier){
			mem = new ConcreteMementoCopier();
		}else if(a instanceof Couper){
			mem = new ConcreteMementoCouper();
		}else if(a instanceof SaisirTexte){
			ConcreteMementoSaisirTexte mem2 = new ConcreteMementoSaisirTexte();
			mem2.set_car(((SaisirTexte) a).getText());
			mem=mem2;
		}else if(a instanceof Supprimer){
			ConcreteMementoSupprimer mem2 = new ConcreteMementoSupprimer();
			mem2.set_sup(((Supprimer) a).get_sup());
			mem=mem2;
		}else{
			System.out.println("Erreur : getmementoUR");
		}
		mem.set_cur(_curseur.copie());
		mem.set_pp(_pressePapier.copie());
		mem.set_sel(_selection.copie());
		_enregistreurUR.enregistrer(mem);
	}
	
	/**
	 * set pour l'originator du memento pour la v3 (undo)
	 * @param m MementoUR
	 */
	public void setMementoU(MementoUR m) {
		if(m instanceof ConcreteMementoColler){
			_selection.setDebutSelect(m.get_cur().getEmplacement());
			_selection.setFinSelect(m.get_cur().getEmplacement()+m.get_pp().size());
			supprimer(true);
			if(m.get_sel().getTailleSelection()!=0){
				_buffer.setChaine(((ConcreteMementoColler) m).get_eleSup());
			}
		}else if(m instanceof ConcreteMementoCopier){
			//rien normal
		}else if(m instanceof ConcreteMementoCouper){
			_selection.setDebutSelect(_curseur.getEmplacement());
			_selection.setFinSelect(_curseur.getEmplacement());
			_curseur.changeCurseur(m.get_sel().getDebutSelect());
			//_pressePapier=m.get_pp();
			coller();
		}else if(m instanceof ConcreteMementoSaisirTexte){
			_selection.setDebutSelect(_curseur.getEmplacement());
			_selection.setFinSelect(_curseur.getEmplacement());
			_curseur.changeCurseur(m.get_cur().getEmplacement()+1);
			supprimer(true);
			if(m.get_sel().getTailleSelection()!=0){
				_buffer.setChaine(((ConcreteMementoColler) m).get_eleSup());
			}
		}else if(m instanceof ConcreteMementoSupprimer){
			if(m.get_sel().getTailleSelection()!=0){
				_curseur.changeCurseur(m.get_sel().getDebutSelect());
			}	
			_buffer.setChaine(((ConcreteMementoSupprimer) m).get_eleSup());
			
		}else{
			System.out.println("Erreur : setmementoU");
		}
		_curseur.changeCurseur(m.get_cur().getEmplacement());
		_pressePapier.set_PressePapier(m.get_pp().get_PressePapier());
		_selection.setDebutSelect(m.get_sel().getDebutSelect());
		_selection.setFinSelect(m.get_sel().getFinSelect());
		_selection.majAffichage();
	}
	
	/**
	 * set pour l'originator du memento pour la v3 (redo)
	 * @param m MementoUR
	 */
	public void setMementoR(MementoUR m) {
		_curseur.changeCurseur(m.get_cur().getEmplacement());
		_pressePapier.set_PressePapier(m.get_pp().get_PressePapier());
		_selection.setDebutSelect(m.get_sel().getDebutSelect());
		_selection.setFinSelect(m.get_sel().getFinSelect());
		_selection.majAffichage();
		if(m instanceof ConcreteMementoColler){
			coller();
		}else if(m instanceof ConcreteMementoCopier){
			copier();
		}else if(m instanceof ConcreteMementoCouper){
			couper();
		}else if(m instanceof ConcreteMementoSaisirTexte){
			ConcreteMementoSaisirTexte m2=(ConcreteMementoSaisirTexte) m;
			saisirText(m2.get_car());
		}else if(m instanceof ConcreteMementoSupprimer){
			ConcreteMementoSupprimer m2=(ConcreteMementoSupprimer) m;
			supprimer(m2.get_sup());
		}else{
			System.out.println("Erreur : setmementoR");
		}
	}
	
	//---------------------------------------------------------------
	//---------------------- getter / setteur -----------------------
	//---------------------------------------------------------------

	/**
	 * Getter sur l'enregistreur de la v2
	 * @return _enregistreur Enregistreur
	 */
	public Enregistreur get_enregistreur() {
		return _enregistreur;
	}
	/**
	 * Getter sur l'enregistreur de la v3
	 * @return _enregistreurUR EnregistreurUR
	 */
	public EnregistreurUR get_enregistreurUR(){
		return _enregistreurUR;
	}
	/**
	 * Getter sur la sauvegarde du dernier element supprime
	 * @return _eleSup String
	 */
	public String get_eleSup(){
		return _eleSup;
	}
}
